package com.msh.artascope.devcloud.service.service.impl;


import com.msh.artascope.devcloud.client.enums.biz.DomainConfigHttpFlagEnum;
import com.msh.artascope.devcloud.client.po.DomainConfigPo;
import com.msh.artascope.devcloud.client.po.EnvPo;
import com.msh.artascope.devcloud.client.qo.DomainConfigQo;
import com.msh.artascope.devcloud.service.dao.DomainConfigDao;
import com.msh.artascope.devcloud.service.define.DevCloudDef;
import com.msh.artascope.devcloud.service.model.query.DomainConfigQueryVo;
import com.msh.artascope.devcloud.service.model.vo.DomainConfigVo;
import com.msh.artascope.devcloud.service.service.DomainConfigService;
import com.msh.artascope.devcloud.service.service.EnvService;
import com.msh.artascope.devcloud.service.service.KubernetesConfigService;
import com.msh.artascope.devcloud.service.wrapper.K8sWrapper;
import com.msh.artascope.devcloud.service.wrapper.K8sWrapper.K8sInfo;
import com.msh.frame.client.base.TenantBaseServiceImpl;
import com.msh.frame.client.common.Result;
import com.msh.frame.client.exception.BizException;
import com.msh.frame.interfaces.IdGenerateable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

/**
 * @author shihu
 * @email m-sh@qq.com
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class DomainConfigServiceImpl extends
    TenantBaseServiceImpl<DomainConfigPo, DomainConfigQo> implements DomainConfigService {

  @Resource
  private DomainConfigDao domainConfigDao;

  @Resource
  private IdGenerateable idGenerateable;
  @Resource
  private K8sWrapper k8sWrapper;
  @Resource
  private EnvService envService;
  @Resource
  private KubernetesConfigService kubernetesConfigService;


  @Override
  public long insert(DomainConfigPo param) {
    param.setId(idGenerateable.getUniqueId());
    return super.insert(param);
  }

  @Override
  public int insertCollection(Collection<DomainConfigPo> param) {
    Long[] uniqueIds = idGenerateable.getUniqueIds(param.size());
    int i = 0;
    for (DomainConfigPo next : param) {
      next.setId(uniqueIds[i++]);
    }
    return super.insertCollection(param);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public Long insertWithGateway(DomainConfigPo p, K8sInfo k8s) {
    long insert = insert(p);
    k8sWrapper.createIstioGateway(k8s, p);
    return insert;
  }

  @Override
  public void updateWithGateway(DomainConfigPo p, K8sInfo k8s) {
    super.update(p);
    k8sWrapper.updateIstioGateway(k8s, p);
  }

  private void updateWithGateway(DomainConfigPo p) {
    K8sInfo k8s = kubernetesConfigService.getK8s(p.getEnvId(), p.getTenantId());
    BizException.doThrowIfNull("无法获取k8s信息", k8s);
    super.update(p);
    k8sWrapper.updateIstioGateway(k8s, p);
  }

  @Override
  public void deleteWithGateway(DomainConfigPo domainConfigPo, K8sInfo k8s, Long tennatId) {
    k8sWrapper.deleteIstioGateway(k8s, DevCloudDef.getGatewayName(domainConfigPo.getDomain()));
    delete(domainConfigPo.getId(), tennatId);
  }

  public void deleteWithGateway(DomainConfigPo domainConfigPo, Long tennatId) {
    K8sInfo k8s = kubernetesConfigService.getK8s(domainConfigPo.getEnvId(), tennatId);
    BizException.doThrowIfNull("无法获取k8s信息", k8s);
    k8sWrapper.deleteIstioGateway(k8s, DevCloudDef.getGatewayName(domainConfigPo.getDomain()));
    delete(domainConfigPo.getId(), tennatId);
  }

// ----------前端vo处理-------------------------------------------------------

  private DomainConfigVo toVo(DomainConfigPo po, EnvPo envPo) {
    DomainConfigVo vo = po.convert(DomainConfigVo.class);
    if (null != envPo) {
      vo.setEnvIdDesc(envPo.getEnv());
    }
    vo.setHttpFlagDesc(DomainConfigHttpFlagEnum.toDesc(po.getHttpFlag()));
    vo.setHttpsFlagDesc(DomainConfigHttpFlagEnum.toDesc(po.getHttpsFlag()));

    return vo;
  }

  private List<DomainConfigVo> toVoList(List<DomainConfigPo> list, Long tenantId) {
    if (CollectionUtils.isEmpty(list)) {
      return Collections.emptyList();
    }
    Set<Long> envIdSet = list
        .stream()
        .map(DomainConfigPo::getEnvId)
        .collect(Collectors.toSet());
    Map<Long, EnvPo> envIdMap = envService.map(envIdSet, tenantId);

    return list.stream().map(po -> {
      return toVo(po, envIdMap.get(po.getEnvId()));
    }).collect(Collectors.toList());
  }

  @Override
  public DomainConfigPo getByEnvId(Long envId, Long tenantId) {
    return listOne(new DomainConfigQo().setEnvId(envId).setTenantId(tenantId));
  }

  @Override
  @Transactional
  public Long insertVo(DomainConfigVo vo) {
    Long tenantId = vo.getTenantId();
    if (!StringUtils.hasText(vo.getTslCert()) && DomainConfigHttpFlagEnum.ENABLE.getValue()
        .equals(vo.getHttpsFlag())) {
      throw new BizException("缺少证书信息");
    }

    Long envId = vo.getEnvId();
    K8sInfo k8s = kubernetesConfigService.getK8s(envId, tenantId);
    BizException.doThrowIfNull("无法获取k8s信息", k8s);
    return insertWithGateway(vo, k8s);
  }

  @Override
  @Transactional
  public void updateVo(DomainConfigVo vo) {
    if (!StringUtils.hasText(vo.getTslCert()) && DomainConfigHttpFlagEnum.ENABLE.getValue()
        .equals(vo.getHttpsFlag())) {
      throw new BizException("缺少证书信息");
    }
    Long tenantId = vo.getTenantId();
    DomainConfigPo db = get(vo.getId(), tenantId);
    boolean isChange = false;
    if (!vo.getHttpFlag().equals(db.getHttpFlag())) {
      db.setHttpFlag(vo.getHttpFlag());
      isChange = true;
    }
    if (!vo.getHttpsFlag().equals(db.getHttpsFlag())) {
      db.setHttpsFlag(vo.getHttpsFlag());
      db.setTslCert(vo.getTslCert());
      isChange = true;
    } else if (DomainConfigHttpFlagEnum.ENABLE.getValue().equals(vo.getHttpsFlag())) {
      if (!vo.getTslCert().equals(db.getTslCert())) {
        db.setTslCert(vo.getTslCert());
        isChange = true;
      }
    }

    if (isChange) {

      db.setUpdateVersion(vo.getUpdateVersion());
      updateWithGateway(db);
    }
  }

  @Override
  @Transactional
  public void deleteVo(Long id, Long tenantId) {
    DomainConfigPo domainConfigPo = get(id, tenantId);
    if (null == domainConfigPo) {
      return;
    }
    deleteWithGateway(domainConfigPo, tenantId);
  }

  @Override
  public DomainConfigVo getVo(Long id, Long tenantId) {
    DomainConfigPo po = this.get(id, tenantId);
    if (null == po) {
      return null;
    }
    EnvPo envPo = envService.get(po.getEnvId(), tenantId);
    DomainConfigVo vo = toVo(po, envPo);

    return vo;
  }

  @Override
  public List<DomainConfigVo> listVo(DomainConfigQueryVo q) {
    DomainConfigQo qo = q.convert(DomainConfigQo.class);
    List<DomainConfigPo> poList = this.list(qo);
    List<DomainConfigVo> voList = toVoList(poList, qo.getTenantId());

    return voList;
  }

  @Override
  public Result<List<DomainConfigVo>> pageVo(DomainConfigQueryVo param) {
    DomainConfigQo qo = param.convert(DomainConfigQo.class);
    int count = this.count(qo);
    if (0 == count) {
      return Result.successReturn(Collections.<DomainConfigVo>emptyList()).setCount(count);
    }
    List<DomainConfigPo> poList = this.list(qo);
    List<DomainConfigVo> voList = toVoList(poList, qo.getTenantId());

    return Result.successReturn(voList).setCount(count);
  }
}
